//package websocket
//
//import (
//	"encoding/json"
//	"fmt"
//	"github.com/gin-gonic/gin"
//	"github.com/gorilla/websocket"
//	"go.uber.org/zap"
//	"goskeleton/app/global/consts"
//	"goskeleton/app/global/my_errors"
//	"goskeleton/app/global/variable"
//	"goskeleton/app/utils/websocket/core"
//)
//
///**
//websocket模块相关事件执行顺序：
//1.onOpen
//2.OnMessage
//3.OnError
//4.OnClose
//*/
//
//type Ws struct {
//	WsClient *core.Client
//}
//
//// OnOpen 事件函数
//func (w *Ws) OnOpen(context *gin.Context) (*Ws, bool) {
//	if client, ok := (&core.Client{}).OnOpen(context); ok {
//
//		token := context.GetString(consts.ValidatorPrefix + "token")
//		variable.ZapLog.Info("获取到的客户端上线时携带的唯一标记值：", zap.String("token", token))
//
//		// 成功上线以后，开发者可以基于客户端上线时携带的唯一参数(这里用token键表示)
//		// 在数据库查询更多的其他字段信息，直接追加在 Client 结构体上，方便后续使用
//		//client.ClientMoreParams.UserParams1 = token
//		//client.ClientMoreParams.UserParams2 = "456"
//		//fmt.Printf("最终每一个客户端(client) 已有的参数：%+v\n", client)
//
//		w.WsClient = client
//		go w.WsClient.Heartbeat() // 一旦握手+协议升级成功，就为每一个连接开启一个自动化的隐式心跳检测包
//		return w, true
//	} else {
//		return nil, false
//	}
//}
//
//// OnMessage 处理业务消息
///*func (w *Ws) OnMessage(context *gin.Context) {
//	go w.WsClient.ReadPump(func(messageType int, receivedData []byte) {
//		//参数说明
//		//messageType 消息类型，1=文本
//		//receivedData 服务器接收到客户端（例如js客户端）发来的的数据，[]byte 格式
//
//		tempMsg := "服务器已经收到了你的消息==>" + string(receivedData)
//		// 回复客户端已经收到消息;
//		if err := w.WsClient.SendMessage(messageType, tempMsg); err != nil {
//			variable.ZapLog.Error("消息发送出现错误", zap.Error(err))
//		}
//
//		fmt.Printf(tempMsg)
//
//	}, w.OnError, w.OnClose)
//}*/
//type Message struct {
//	TargetUser string `json:"target_user"`
//	Content    string `json:"content"`
//}
//
//func (w *Ws) OnMessage(context *gin.Context) {
//	go w.WsClient.ReadPump(func(messageType int, receivedData []byte) {
//		// 参数说明
//		// messageType 消息类型，1=文本
//		// receivedData 服务器接收到客户端（例如js客户端）发来的的数据，[]byte 格式
//
//		// 解析收到的 JSON 数据
//		var msg Message
//		err := json.Unmarshal(receivedData, &msg)
//		if err != nil {
//			variable.ZapLog.Error("解析消息时出错", zap.Error(err))
//			return
//		}
//
//		// 打印解析后的内容
//		tempMsg := fmt.Sprintf("服务器已经收到了你的消息==> TargetUser: %s, Content: %s", msg.TargetUser, msg.Content)
//
//		// 回复客户端已经收到消息
//		if err := w.WsClient.SendMessage(messageType, tempMsg); err != nil {
//			variable.ZapLog.Error("消息发送出现错误", zap.Error(err))
//		}
//
//		//发送信息给特定用户
//		if err := w.SendToUser(msg.TargetUser, messageType, tempMsg); err != nil {
//			variable.ZapLog.Error("向特定用户发送消息时出错", zap.Error(err))
//		}
//
//		// 输出接收到的消息
//		fmt.Println(tempMsg)
//	}, w.OnError, w.OnClose)
//}
//
//// OnError 客户端与服务端在消息交互过程中发生错误回调函数
//func (w *Ws) OnError(err error) {
//	w.WsClient.State = 0 // 发生错误，状态设置为0, 心跳检测协程则自动退出
//	variable.ZapLog.Error("远端掉线、卡死、刷新浏览器等会触发该错误:", zap.Error(err))
//	//fmt.Printf("远端掉线、卡死、刷新浏览器等会触发该错误: %v\n", err.Error())
//}
//
//// OnClose 客户端关闭回调，发生onError回调以后会继续回调该函数
//func (w *Ws) OnClose() {
//
//	w.WsClient.Hub.UnRegister <- w.WsClient // 向hub管道投递一条注销消息，由hub中心负责关闭连接、删除在线数据
//}
//
//// GetOnlineClients  获取在线的全部客户端
//func (w *Ws) GetOnlineClients() {
//
//	fmt.Printf("在线客户端数量：%d\n", len(w.WsClient.Hub.Clients))
//}
//
//// BroadcastMsg  (每一个客户端都有能力)向全部在线客户端广播消息
//func (w *Ws) BroadcastMsg(sendMsg string) {
//	for onlineClient := range w.WsClient.Hub.Clients {
//
//		//获取每一个在线的客户端，向远端发送消息
//		if err := onlineClient.SendMessage(websocket.TextMessage, sendMsg); err != nil {
//			variable.ZapLog.Error(my_errors.ErrorsWebsocketWriteMgsFail, zap.Error(err))
//		}
//	}
//}
//
//// 向特定用户发送消息
//func (w *Ws) SendToUser(targetUser string, messageType int, content string) error {
//	for client := range w.WsClient.Hub.Clients {
//		// 假设 ClientMoreParams.UserParams1 存储了用户的唯一标识
//		if client.ClientMoreParams.UserParams1 == targetUser {
//			return client.SendMessage(messageType, content)
//		}
//	}
//	return fmt.Errorf("目标用户未找到: %s", targetUser)
//}

package websocket

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"go.uber.org/zap"
	"goskeleton/app/global/consts"
	"goskeleton/app/global/my_errors"
	"goskeleton/app/global/variable"
	"goskeleton/app/model"
	"goskeleton/app/utils/websocket/core"
	"sync"
)

/**
websocket模块相关事件执行顺序：
1.onOpen
2.OnMessage
3.OnError
4.OnClose
*/

// 全局存储用户连接的 map
var (
	clientsMap      = make(map[string]*core.Client) // key: 用户唯一标识, value: WebSocket 客户端
	offlineMessages = make(map[string][]string)     // key: 用户唯一标识, value: 离线消息列表
	mapMutex        sync.RWMutex                    // 保护 clientsMap 和 offlineMessages 的并发访问
)

type Ws struct {
	WsClient *core.Client
}

// OnOpen 事件函数
func (w *Ws) OnOpen(context *gin.Context) (*Ws, bool) {
	if client, ok := (&core.Client{}).OnOpen(context); ok {
		token := context.GetString(consts.ValidatorPrefix + "token")
		variable.ZapLog.Info("获取到的客户端上线时携带的唯一标记值：", zap.String("token", token))

		// 将用户唯一标识与客户端关联
		client.ClientMoreParams.UserParams1 = token
		AddClient(token, client)

		// 检查是否有离线消息
		messages := GetAndClearOfflineMessages(token)
		for _, msg := range messages {
			client.SendMessage(websocket.TextMessage, msg)
		}

		w.WsClient = client
		go w.WsClient.Heartbeat() // 开启心跳检测
		return w, true
	} else {
		return nil, false
	}
}

// OnMessage 处理业务消息
type Message struct {
	TargetUser string `json:"target_user"`
	Content    string `json:"content"`
}

func (w *Ws) OnMessage(context *gin.Context) {
	go w.WsClient.ReadPump(func(messageType int, receivedData []byte) {
		// 解析收到的 JSON 数据
		var msg Message
		err := json.Unmarshal(receivedData, &msg)
		if err != nil {
			variable.ZapLog.Error("解析消息时出错", zap.Error(err))
			return
		}

		// 打印解析后的内容
		/*		tempMsg := fmt.Sprintf("服务器已经收到了你的消息==> TargetUser: %s, Content: %s", msg.TargetUser, msg.Content)

				// 回复客户端已经收到消息
				if err := w.WsClient.SendMessage(messageType, tempMsg); err != nil {
					variable.ZapLog.Error("消息发送出现错误", zap.Error(err))
				}*/

		//在发送特定信息前先检查是否有两用户之间的聊天确保是这两个用户之间的交流
		w.isChatRecord(w.WsClient.ClientMoreParams.UserParams1, msg.TargetUser)

		// 发送信息给特定用户
		if err := w.SendToUser(msg, messageType); err != nil {
			variable.ZapLog.Error("向特定用户发送消息时出错", zap.Error(err))
		}

		// 输出接收到的消息
		//fmt.Println(tempMsg)
		fmt.Printf(msg.Content)
	}, w.OnError, w.OnClose)
}

// 排查用户间是否有聊天记录
func (w *Ws) isChatRecord(senderOpenId, receiverOpenId string) {
	model.CreateChatFactory2("mysql").CreateChatRecord(senderOpenId, receiverOpenId)
}

// 保存用户间的消息聊天
func (w *Ws) saveChat(msg Message, status int) {
	model.CreateChatFactory1("mysql").CreateChat(w.WsClient.ClientMoreParams.UserParams1, msg.TargetUser, msg.Content, status)
}

// OnError 客户端与服务端在消息交互过程中发生错误回调函数
func (w *Ws) OnError(err error) {
	w.WsClient.State = 0 // 发生错误，状态设置为0, 心跳检测协程则自动退出
	variable.ZapLog.Error("远端掉线、卡死、刷新浏览器等会触发该错误:", zap.Error(err))
}

// OnClose 客户端关闭回调，发生onError回调以后会继续回调该函数
func (w *Ws) OnClose() {
	// 获取用户唯一标识
	userKey := w.WsClient.ClientMoreParams.UserParams1
	RemoveClient(userKey)

	w.WsClient.Hub.UnRegister <- w.WsClient // 向hub管道投递一条注销消息
}

// GetOnlineClients 获取在线的全部客户端
func (w *Ws) GetOnlineClients() {
	fmt.Printf("在线客户端数量：%d\n", len(w.WsClient.Hub.Clients))
}

// BroadcastMsg 向全部在线客户端广播消息
func (w *Ws) BroadcastMsg(sendMsg string) {
	for onlineClient := range w.WsClient.Hub.Clients {
		// 获取每一个在线的客户端，向远端发送消息
		if err := onlineClient.SendMessage(websocket.TextMessage, sendMsg); err != nil {
			variable.ZapLog.Error(my_errors.ErrorsWebsocketWriteMgsFail, zap.Error(err))
		}
	}
}

// SendToUser 向特定用户发送消息
func (w *Ws) SendToUser(msg Message, messageType int) error {
	client, exists := GetClient(msg.TargetUser)
	if !exists {
		// 如果目标用户不在线，存储为离线消息
		//StoreOfflineMessage(msg.TargetUser, msg.Content)
		//存储用户之间的聊天信息,标记为未读的信息
		w.saveChat(msg, 0)
		return fmt.Errorf("目标用户未找到: %s", msg.TargetUser)
	}
	//存储用户之间的聊天信息,标记为已读的信息
	w.saveChat(msg, 1)
	// 目标用户在线，直接发送消息
	return client.SendMessage(messageType, msg.Content)
}

// 添加用户连接
func AddClient(userKey string, client *core.Client) {
	mapMutex.Lock()
	defer mapMutex.Unlock()
	clientsMap[userKey] = client
}

// 删除用户连接
func RemoveClient(userKey string) {
	mapMutex.Lock()
	defer mapMutex.Unlock()
	delete(clientsMap, userKey)
}

// 获取用户连接
func GetClient(userKey string) (*core.Client, bool) {
	mapMutex.RLock()
	defer mapMutex.RUnlock()
	client, exists := clientsMap[userKey]
	return client, exists
}

// 存储离线消息
func StoreOfflineMessage(userKey, message string) {
	mapMutex.Lock()
	defer mapMutex.Unlock()

	offlineMessages[userKey] = append(offlineMessages[userKey], message)
}

// 获取并清空离线消息
func GetAndClearOfflineMessages(userKey string) []string {
	mapMutex.Lock()
	defer mapMutex.Unlock()

	messages := offlineMessages[userKey]
	delete(offlineMessages, userKey)
	return messages
}
